﻿ 

namespace Common.Algorithm.Core;

public class QuantumGeneticService
{
    #region builder

    private static Random randomBuilder { get; set; } = new Random();
    //private static VectorBuilder<double> vectorBuilder { get; set; } = Vector<double>.Build;

    //private static MatrixBuilder<double> matBuilder { get; set; } = Matrix<double>.Build;

    #endregion

    #region data

    /// <summary>
    /// 量子序列长
    /// </summary>
    public static int sequenceLen { get; set; } = 0;
    /// <summary>
    /// 需要使用的量子序列的数量
    /// </summary>
    public int populationSize { get; set; } = 10;
     
    /// <summary>
    /// 量子群 多个量子序列的集合
    /// </summary>
    public static List<Quant[]> sequences { get; set; } = new List<Quant[]>();

    /// <summary>
    /// 目标函数
    /// </summary>
    public static Func<double[], double> targetFunc { get; set; } = (pnt) => { return 0; };

    /// <summary>
    /// 二进制解码函数
    /// </summary>
    public static Func<int[], double[]> decodeFunc { get; set; } = (binary) => { return new double[1]; };

    /// <summary>
    /// 当前最佳量子
    /// </summary>
    public static Quant[] bestSequence { get; set; }

    /// <summary>
    /// 量子门选旋转角度判断字典
    /// </summary>
    public static Dictionary<string, double> thetaDict { get; set; } = new Dictionary<string, double>();
      
    #endregion

    #region init 

    public QuantumGeneticService(int _sequenceLen, int _populationSize)
    {
        //初始化量子自旋角度判断表
        thetaDict = GenThetaDict();

        sequenceLen = _sequenceLen;
        populationSize = _populationSize;

        sequences.Clear();
        //建立量子群
        for (int i = 0; i < populationSize; i++)
        {
            List<Quant> sequence = new List<Quant>();
            for (int j = 0; j < sequenceLen; j++)
            {
                sequence.Add(new Quant() { id = new int[] { i, j } });
            }
            sequences.Add(sequence.ToArray());
        }
    }
    private static Dictionary<string, double> GenThetaDict()
    {
        var sign = Math.Sign(randomBuilder.NextDouble() - 0.5d);
        Dictionary<string, double> pairs = new Dictionary<string, double>();

        pairs.Add("0000", 0);
        pairs.Add("0010", 0);

        pairs.Add("0101", +1d);
        pairs.Add("0102", -1d);
        pairs.Add("0103", 0d);
        pairs.Add("0104", -1d * sign);
        pairs.Add("0111", -1d);
        pairs.Add("0112", 1d);
        pairs.Add("0113", 1d * sign);
        pairs.Add("0114", 0d);
        pairs.Add("1001", -1d);
        pairs.Add("1002", 1d);
        pairs.Add("1003", 1d * sign);
        pairs.Add("1004", 0d);
        pairs.Add("1011", 1d);
        pairs.Add("1012", -1d);
        pairs.Add("1013", 0d);
        pairs.Add("1014", 1d * sign);

        pairs.Add("1100", 0);
        pairs.Add("1110", 0);

        return pairs;
    }

    #endregion

    public void Run(int numberOfGeneration)
    {
        while (numberOfGeneration > 0)
        {
            numberOfGeneration--;

            //集体测量进行量子塌缩
            Parallel.ForEach(sequences, (sequence) =>
            {
                sequence.ToList().ForEach(q => q.Collapse());
            });

            //寻找最优
            double minTag = double.MaxValue; 
            foreach (var sequence in sequences)
            {
                var binary = sequence.Select(q => q.collapsedValue).ToArray();
                var comment = targetFunc(decodeFunc(binary));
                if (comment < minTag)
                {
                    minTag = comment;
                    bestSequence = sequence;
                }
            }

            //量子门旋转 ROTATE
            Parallel.ForEach(sequences, (sequence) =>
            {
                var thetas = GenTheta(sequence);
                //Console.WriteLine(string.Join("|", thetas));
                sequence.ToList().ForEach(q => q.Rotate());
            });

        }
    }

    public static double[] GenTheta(Quant[] currSequence)
    {
        List<double> thetas = new List<double>();

        var currBinary = currSequence.Select(q => q.collapsedValue).ToArray();
        var bestBinary = bestSequence.Select(q => q.collapsedValue).ToArray();

        int fxfb =
            targetFunc(decodeFunc(currBinary)) -
            targetFunc(decodeFunc(bestBinary)) > 0 ? 1 : 0;
        for (int i = 0; i < currSequence.Length; i++)
        {

            var currQ = currSequence[i];
            var bestQ = bestSequence[i];

            int xi = currBinary[i];
            int bi = bestBinary[i];

            if (xi == bi) { thetas.Add(0); currQ.theta = 0; continue; }

            int sign = 0;
            if (currQ.alpha * currQ.beta > 0d)
                sign = 1;
            else if (currQ.alpha * currQ.beta < 0d)
                sign = 2;
            else if (currQ.alpha == 0)
                sign = 3;
            else if (currQ.beta == 0)
                sign = 4;

            //sign = currQ.alpha * currQ.beta > 0d ? 1 : 0;
            //sign = currQ.alpha * currQ.beta < 0d ? 2 : 0;
            //sign = currQ.alpha == 0 ? 3 : 0;
            //sign = currQ.beta == 0 ? 4 : 0;

            List<double> arrs = new List<double>();
            arrs.Add(xi);
            arrs.Add(bi);
            arrs.Add(fxfb);
            arrs.Add(sign);

            var theta = thetaDict[string.Join("", arrs.ToArray())];
            currQ.theta = theta;

            thetas.Add(theta);

        }
        return thetas.ToArray();
    }

    public static string GetResult()
    {
        List<int> values = bestSequence.Select(q => q.collapsedValue).ToList();
        List<double> doubles = decodeFunc(values.ToArray()).ToList();
        return string.Join(",", doubles);
    }

    // <summary>
    /// ======================
    /// </summary>
    public class Quant
    {
        private static Random randomBuilder { get; set; } = new Random();
        //private static VectorBuilder<double> vectorBuilder { get; set; } = Vector<double>.Build;

        public Quant(double _alpha)
        {
            this.id = new int[] { 0, 0 };
            this.alpha = _alpha;
            this.beta = GetBeta();
        }

        /// <summary>
        /// 默认等概率初始化
        /// </summary>
        public Quant()
        {
            this.id = new int[] { 0, 0 };
            this.alpha = 1d / Math.Sqrt(2);
            this.beta = 1d / Math.Sqrt(2);
        }

        public int Collapse()
        {
            var tag = randomBuilder.NextDouble();
            var res = Math.Pow(this.alpha, 2) < tag ? 0 : 1;
            collapsedValue = res;
            return res;
        }
        /// <summary>
        /// 根据纠缠态原则获得alpha
        /// </summary>
        /// <returns></returns>
        public double GetAlpha()
        {
            return Math.Sqrt(1 - this.beta * this.beta);
        }
        /// <summary>
        /// 根据纠缠态原则获得beta
        /// </summary>
        /// <returns></returns>
        public double GetBeta()
        {
            return Math.Sqrt(1 - this.alpha * this.alpha);
        }

        //public Vector<double> ToVector()
        //{
        //    var vec = vectorBuilder.Dense(2);
        //    vec[0] = this.alpha;
        //    vec[1] = this.beta;
        //    return vec;
        //}

        /// <summary>
        /// 量子旋转门
        /// </summary>
        public void Rotate()
        {
            var angle = this.theta * 0.01 * Math.PI;
            var a = this.alpha * Math.Cos(angle) - this.beta * Math.Sin(angle);
            var b = this.alpha * Math.Sin(angle) + this.beta * Math.Cos(angle);

            this.alpha = a;
            this.beta = b;
        }

        /// <summary>
        /// 编号
        /// </summary>
        public int[] id { get; set; }

        /// <summary>
        /// alpha态
        /// </summary>
        public double alpha { get; set; }

        /// <summary>
        /// beta态
        /// </summary>
        public double beta { get; set; }
        /// <summary>
        /// 测量塌缩所得值
        /// </summary>
        public int collapsedValue { get; set; }

        /// <summary>
        /// 量子此次需要旋转的角度
        /// </summary>
        public double theta { get; set; }
    }

}

